#include "vc1dec_definitions.h"
#include "vc1stream.h"

static void VC1AppendCache(sVC1Stream* pStream)
{
	I32_VC1 remain = 0;
	I32_VC1 num = 0,need = 0, i = 0;
	U8_VC1* pStart = pStream->pStreamStart + pStream->ByteUsed;
	remain = pStream->pStreamEnd - pStart;
	need = pStream->BitUsed >> 3;

	num = MIN(need,remain);
	pStream->Cache <<= (num<<3);
	switch(num)
	{
	case 0:
		return;
	case 1:
		pStream->Cache |= pStart[0];
		pStream->BitUsed -= 8;
		pStream->ByteUsed += 1;
		break;
	case 2:
		pStream->Cache |= (pStart[0]<<8) | pStart[1];
		pStream->BitUsed -= 16;
		pStream->ByteUsed += 2;
		break;
	case 3:
		pStream->Cache |= (pStart[0]<<16) | (pStart[1]<<8) | pStart[2];
		pStream->BitUsed -= 24;
		pStream->ByteUsed += 3;
		break;
	case 4:
		pStream->Cache = (pStart[0]<<24) | (pStart[1]<<16) | (pStart[2]<<16) | pStart[3];
		pStream->BitUsed -= 32;
		pStream->ByteUsed += 4;
		break;
	} 

}


static U32_VC1 VC1FillCache(sVC1Stream* pStream)
{
	I32_VC1 remain = 0;
	I32_VC1 num = 0, i = 0;
	U8_VC1* pStart = pStream->pStreamStart + pStream->ByteUsed;
	remain = pStream->pStreamEnd - pStart;

	if(remain <= 0)
		return STREAM_EOF;

	num = MIN(4,remain);
	pStream->Cache = 0;
	switch(num)
	{
	case 1:
		pStream->Cache = pStart[0];
		pStream->BitUsed = 24;
		pStream->ByteUsed += 1;
		break;
	case 2:
		pStream->Cache = (pStart[0]<<8) | pStart[1];
		pStream->BitUsed = 16;
		pStream->ByteUsed += 2;
		break;
	case 3:
		pStream->Cache = (pStart[0]<<16) | (pStart[1]<<8) | pStart[2];
		pStream->BitUsed = 8;
		pStream->ByteUsed += 3;
		break;
	case 4:
		pStream->Cache = (pStart[0]<<24) | (pStart[1]<<16) | (pStart[2]<<16) | pStart[3];
		pStream->BitUsed = 0;
		pStream->ByteUsed += 4;
		break;
	}

	return STREAM_SUCCEEDED;
}

U32_VC1 VC1InitStream(sVC1Stream* pStream, U8_VC1* pBuffer, I32_VC1 iLen)
{
	if(!pStream || !pBuffer || iLen <= 0)
		return STREAM_INVALIDBUFFER;

	pStream->pStreamStart = pBuffer;
	pStream->pStreamEnd = pBuffer + iLen;
	pStream->BitUsed = 0;
	pStream->BitValid = 0;
	pStream->ByteUsed = 0;

	VC1FillCache(pStream);
	return STREAM_SUCCEEDED;
}

U32_VC1 VC1GetBits(sVC1Stream* pStream,I32_VC1 iBits)
{
	I32_VC1 bitUsed = pStream->BitUsed;
	U32_VC1 result = 0;
	if(pStream->BitUsed >= 32)
	{
		if(VC1FillCache(pStream) == STREAM_EOF)
			return STREAM_EOF;
	}

	if((32 - bitUsed) < iBits)///bits insufficient
	{
		I32_VC1 tmp = iBits - 32 + bitUsed;
		result = (pStream->Cache << bitUsed) >> bitUsed;

		if(VC1FillCache(pStream) == STREAM_EOF)
			return STREAM_EOF;
		
		////
		result = (result<<tmp) | (pStream->Cache >> (32 - pStream->BitUsed - tmp));
		pStream->BitUsed += tmp;
	}
	else
	{
		result = (pStream->Cache << pStream->BitUsed) >> (32 - iBits);
		pStream->BitUsed += iBits;
	}

	return result;
}

U32_VC1 VC1GetBit1(sVC1Stream* pStream)
{
	return 0;
}

/////This function is buggy when (iBits > rest && rest > 24)
U32_VC1 VC1ShowBits(sVC1Stream* pStream,I32_VC1 iBits)
{
	I32_VC1 rest = 32 - pStream->BitUsed;
	U32_VC1 result = 0;
	
	if(rest < iBits)///bits insufficient
	{
		VC1AppendCache(pStream);
		rest = 32 - pStream->BitUsed;
		if(rest < iBits)
			return STREAM_EOF;
	}

	result = (pStream->Cache << pStream->BitUsed) >> (32 - iBits);

	return result;
}

/////This function is buggy when (iBits > rest && rest > 24)
U32_VC1 VC1DumpBits(sVC1Stream* pStream,I32_VC1 iBits)
{
	I32_VC1 rest = 32 - pStream->BitUsed;
	
	if(rest < iBits)///bits insufficient
	{
		VC1AppendCache(pStream);
		rest = 32 - pStream->BitUsed;
		if(rest < iBits)
			return STREAM_EOF;
	}

	pStream->BitUsed += iBits;

	return 0;
}